/*******************************************************************************
  * 文件：OS_Timer.c
  * 作者：zyz
  * 版本：v2.1.0
  * 日期：2020-08-17
  * 说明：定时器
*******************************************************************************/

/* 头文件 *********************************************************************/
#include "OS_Timer.h"
#include "Hardware.h"
#include "Hardware_WDT.h"
#include "OS_Kernel.h"

/* 宏定义 *********************************************************************/
/* 类型定义 *******************************************************************/
/* 变量定义 *******************************************************************/
static TimerControl_ts sTimerCtrl;    // 定时器控制

/* 函数声明 *******************************************************************/
/* 函数定义 *******************************************************************/
/*******************************************************************************
  * 函数名: OS_TimerInit
  * 功  能：初始化
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerInit(void)
{
    // 初始化链表
    OS_ListInit(&(sTimerCtrl.sTimerList1));
    OS_ListInit(&(sTimerCtrl.sTimerList2));
    OS_ListInit(&(sTimerCtrl.sTimerList3));

    // 初始化定时器链表指针
    sTimerCtrl.psCurrentTimerList  = &(sTimerCtrl.sTimerList1);
    sTimerCtrl.psOverflowTimerList = &(sTimerCtrl.sTimerList2);
    sTimerCtrl.psStagingTimerList  = &(sTimerCtrl.sTimerList3);

    // 初始化定时器节拍
    sTimerCtrl.u16TimerTick = OS_GetSysTick();
}

/*******************************************************************************
  * 函数名: OS_TimerTask
  * 功  能：定时器任务
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerTask(void)
{
    ListNode_ts *psNode;

    // 定时器任务处理
    while(sTimerCtrl.u16TimerTick != OS_GetSysTick())
    {
        // 喂看门狗
        Hardware_RestartWDT();
        
        // 更新定时器节拍
        sTimerCtrl.u16TimerTick++;

        // 进入临界区
        Hardware_EnterCritical();

        // 定时器节拍溢出
        if(sTimerCtrl.u16TimerTick == 0)
        {
            // 交换定时器链表
            List_ts *psTempList;
            psTempList = sTimerCtrl.psCurrentTimerList;
            sTimerCtrl.psCurrentTimerList  = sTimerCtrl.psOverflowTimerList;
            sTimerCtrl.psOverflowTimerList = sTimerCtrl.psStagingTimerList;
            sTimerCtrl.psStagingTimerList  = psTempList;
        }

        // 处理到期定时器
        for(psNode = sTimerCtrl.psCurrentTimerList->sListHead.psNext;
            (psNode->u16NodeValue <= sTimerCtrl.u16TimerTick) &&
            (psNode != &(sTimerCtrl.psCurrentTimerList->sListTail));
            psNode = sTimerCtrl.psCurrentTimerList->sListHead.psNext)
        {
            U32 u32Temp;
            Timer_ts *psTimer;

            // 更新到期次数
            psTimer = (Timer_ts *)(psNode->pvData);
            if(psTimer->u16ExpiredTimes < u16TIMER_EXPIRED_TIMES_MAX_VALUE)
            {
                (psTimer->u16ExpiredTimes)++;
            }

            // 移除节点
            OS_ListRemove(psNode);

            // 计算下次到期节拍
            //u32Temp = OS_GetTick();
            //u32Temp = sTimerCtrl.u16TimerTick;
            u32Temp = psNode->u16NodeValue;
            u32Temp = (U32)(u32Temp + psTimer->u16Period);
            psNode->u16NodeValue = (U16)u32Temp;

            // 溢出当前定时器链表
            if(u32Temp > u16LIST_MAX_NODE_VALUE)
            {
                // 插入到溢出定时器链表
                OS_ListInsertByValue(sTimerCtrl.psOverflowTimerList, psNode);
            }
            // 未溢出当前定时器链表
            else
            {
                // 插入到当前定时器链表
                OS_ListInsertByValue(sTimerCtrl.psCurrentTimerList, psNode);
            }

            // 退出临界区
            Hardware_ExitCritical();

            // 执行回调函数
            if(psTimer->psCallback.pfHandler != NULL)
            {
                psTimer->psCallback.pfHandler(psTimer->psCallback.u32Parameter);
            }

            // 进入临界区
            Hardware_EnterCritical();
        }

        // 退出临界区
        Hardware_ExitCritical();
    }
}

/*******************************************************************************
  * 函数名: OS_TimerStart
  * 功  能：开启定时器
  * 参  数：TimerHandle_tps psTimer    - 定时器句柄
  *         U16 u16Period              - 定时周期
  *         TaskHandler_tpf pfCallback - 回调函数
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerStart(TimerHandle_tps psTimer,
                   U16 u16Period,
                   TaskHandler_tpf pfCallback)
{
    // 开启定时器
    OS_TimerStartEx(psTimer,
                    u16Period,
                    (TaskHandlerEx_tpf)pfCallback,
                    NULL);
}

/*******************************************************************************
  * 函数名: OS_TimerStartEx
  * 功  能：开启(拓展)定时器
  * 参  数：TimerHandle_tps psTimer      - 定时器句柄
  *         U16 u16Period                - 定时周期
  *         TaskHandlerEx_tpf pfCallback - 回调函数
  *         U32 u32Parameter             - 回调函数参数
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerStartEx(TimerHandle_tps psTimer,
                     U16 u16Period,
                     TaskHandlerEx_tpf pfCallback,
                     U32 u32Parameter)
{
    U32 u32Temp;
    U16 u16SysTick;

    // 确保定时器未开启
    if(OS_TimerIsActive(psTimer) == FALSE)
    {
        // 设置定时器参数
        psTimer->u16Period  = u16Period;                    // 定时周期
        psTimer->psCallback.pfHandler = pfCallback;         // 回调函数
        psTimer->psCallback.u32Parameter = u32Parameter;    // 回调函数参数
        psTimer->psCallback.eRunType = eTASK_RUN_ONCE;      // 单次任务
        psTimer->u16ExpiredTimes = 0;                       // 到期次数
        psTimer->sListNode.pvData = (void*)psTimer;         // 设置定时节点

        // 计算下次到期节拍
        u16SysTick = OS_GetSysTick();
        u32Temp = u16SysTick;
        u32Temp = (U32)(u32Temp + psTimer->u16Period);
        psTimer->sListNode.u16NodeValue = (U16)u32Temp;

        // 进入临界区
        Hardware_EnterCritical();

        // 系统节拍未溢出当前链表
        if(u16SysTick >= sTimerCtrl.u16TimerTick)
        {
            // 到期节拍溢出当前定时器链表
            if(u32Temp > u16LIST_MAX_NODE_VALUE)
            {
                // 插入到溢出定时器链表
                OS_ListInsertByValue(sTimerCtrl.psOverflowTimerList,
                                     &psTimer->sListNode);
            }
            // 到期节拍未溢出当前定时器链表
            else
            {
                // 插入到当前定时器链表
                OS_ListInsertByValue(sTimerCtrl.psCurrentTimerList,
                                     &psTimer->sListNode);
            }
        }
        // 系统节拍溢出当前链表
        else
        {
            // 到期节拍溢出当前定时器链表
            if(u32Temp > u16LIST_MAX_NODE_VALUE)
            {
                // 插入到暂存定时器链表
                OS_ListInsertByValue(sTimerCtrl.psStagingTimerList,
                                     &psTimer->sListNode);
            }
            // 到期节拍未溢出当前定时器链表
            else
            {
                // 插入到溢出定时器链表
                OS_ListInsertByValue(sTimerCtrl.psOverflowTimerList,
                                     &psTimer->sListNode);
            }
        }

        // 退出临界区
        Hardware_ExitCritical();
    }
}

/*******************************************************************************
  * 函数名: OS_TimerStop
  * 功  能：停止定时器
  * 参  数：TimerHandle_tps psTimer - 定时器句柄
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerStop(TimerHandle_tps psTimer)
{
    // 如果定时器已开启
    if(OS_TimerIsActive(psTimer) == TRUE)
    {
        // 移除定时器节点
        Hardware_EnterCritical();
        OS_ListRemove(&psTimer->sListNode);
        Hardware_ExitCritical();
    }
}

/*******************************************************************************
  * 函数名: OS_TimerRestart
  * 功  能：重启定时器
  * 参  数：TimerHandle_tps psTimer    - 定时器句柄
  *         U16 u16Period              - 定时周期
  *         TaskHandler_tpf pfCallback - 回调函数
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerRestart(TimerHandle_tps psTimer,
                       U16 u16Period,
                       TaskHandler_tpf pfCallback)
{
    // 先停止定时器，再开始
    OS_TimerStop(psTimer);
    OS_TimerStart(psTimer, u16Period, pfCallback);
}

/*******************************************************************************
  * 函数名: OS_TimerRestartEx
  * 功  能：重启(拓展)定时器
  * 参  数：TimerHandle_tps psTimer      - 定时器句柄
  *         U16 u16Period                - 定时周期
  *         TaskHandlerEx_tpf pfCallback - 回调函数
  *         U32 u32Parameter             - 回调函数参数
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerRestartEx(TimerHandle_tps psTimer,
                       U16 u16Period,
                       TaskHandlerEx_tpf pfCallback,
                       U32 u32Parameter)
{
    // 先停止定时器，再开始
    OS_TimerStop(psTimer);
    OS_TimerStartEx(psTimer, u16Period, pfCallback, u32Parameter);
}

/*******************************************************************************
  * 函数名: OS_TimerReset
  * 功  能：重置定时器
  * 参  数：TimerHandle_tps psTimer - 定时器句柄
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerReset(TimerHandle_tps psTimer)
{
    U16 u16Period;
    TaskHandlerEx_tpf pfCallback;
    U32 u32Parameter;

    // 定时器开启状态下，才能进行重置
    if(OS_TimerIsActive(psTimer) == TRUE)
    {
        // 获取定时周期和回调函数
        u16Period    = psTimer->u16Period;
        pfCallback   = psTimer->psCallback.pfHandler;
        u32Parameter = psTimer->psCallback.u32Parameter;

        // 重启定时器
        OS_TimerRestartEx(psTimer, u16Period, pfCallback, u32Parameter);
    }
}

/*******************************************************************************
  * 函数名: OS_TimerIsActive
  * 功  能：定时器是否开启
  * 参  数：TimerHandle_tps psTimer - 定时器句柄
  * 返回值：无
  * 说  明：无
*******************************************************************************/
Bool OS_TimerIsActive(TimerHandle_tps psTimer)
{
    Bool bReturn = FALSE;

    // 判断所属链表
    if((psTimer->sListNode.psContainer == sTimerCtrl.psCurrentTimerList) ||
       (psTimer->sListNode.psContainer == sTimerCtrl.psOverflowTimerList) ||
       (psTimer->sListNode.psContainer == sTimerCtrl.psStagingTimerList))
    {
        bReturn = TRUE;
    }

    // 返回结果
    return bReturn;
}

/*******************************************************************************
  * 函数名: OS_TimerClearExpiredTimes
  * 功  能：清零到期次数
  * 参  数：TimerHandle_tps psTimer - 定时器句柄
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void OS_TimerClearExpiredTimes(TimerHandle_tps psTimer)
{
    // 清零到期次数
    psTimer->u16ExpiredTimes = 0;
}

/*******************************************************************************
  * 函数名: OS_TimerGetExpiredTimes
  * 功  能：获取定时器到期次数
  * 参  数：TimerHandle_tps psTimer - 定时器句柄
  * 返回值：无
  * 说  明：无
*******************************************************************************/
U16 OS_TimerGetExpiredTimes(TimerHandle_tps psTimer)
{
    // 返回到期次数
    return (psTimer->u16ExpiredTimes);
}

/*******************************************************************************
  * 函数名: OS_TimerGetNumber
  * 功  能：获取定时器个数
  * 参  数：无
  * 返回值：定时器个数
  * 说  明：无
*******************************************************************************/
U16 OS_TimerGetNumber(void)
{
    U16 u16Number;

    // 计算定时器个数
    u16Number = sTimerCtrl.psCurrentTimerList->u16NodesNum +
                sTimerCtrl.psOverflowTimerList->u16NodesNum +
                sTimerCtrl.psStagingTimerList->u16NodesNum;

    // 返回个数
    return u16Number;
}

/***************************** 文件结束 ***************************************/
